from collections.abc import Generator
import time

from assertpy import assert_that
from playwright.sync_api import BrowserContext, Page, APIRequestContext, expect
import pytest

from utils.api import fetch_colocation_config, fetch_volcano_config, fetch_all_node, fetch_node
from utils.constants import COLOCATION_CONFIGS
import actions.colocation.colocation_configuration as cc


pytest.mark.usefixtures("login_and_store_state")


@pytest.fixture(scope='function')
def conf_page(context: BrowserContext) -> Generator[Page, None, None]:
    """混部策略配置页面"""
    page = context.new_page()
    cc.visit_colocation_config_page(page)
    yield page
    page.close()


class TestConfugurationPage:
    """
    @description 测试混部配置页面的主要交互，包括：
    - 页面组件交互功能：搜索框、表格、刷新按钮、混部开关
    """
    @staticmethod
    def test_type_content_in_searchbox(conf_page: Page):
        """Test 43"""
        test_input = 'test'
        searchbox = cc.get_searchbox(conf_page)
        searchbox.fill(test_input)
        expect(searchbox).to_have_value(test_input)

    @staticmethod
    def test_check_search_results(conf_page: Page):
        """Test 44"""
        # test on no matches
        no_match_input = 'qwertyuiop'
        cc.do_node_seach(conf_page, no_match_input)
        node_switches = cc.get_colocation_switches(conf_page)   # antd 表格无数据时会有一个默认空行，这里用开关的数量代替
        assert_that(node_switches).is_length(0)

        # test on matches
        match_input = 'worker'
        cc.do_node_seach(conf_page, match_input)
        node_names = cc.get_node_name(conf_page)
        for node in node_names:
            node_text = node.text_content()
            assert_that(node_text).contains(match_input)

    @staticmethod
    def test_searchbox_should_limit_the_input_length(conf_page: Page):
        """Test 45"""
        length_limit = 53   # default length limit is 53, but why?
        searchbox = cc.get_searchbox(conf_page)
        searchbox.fill('a' * 255)
        expect(searchbox).to_have_value('a' * length_limit)

    @staticmethod
    def test_should_make_a_request_by_clicking_refresh_button(conf_page: Page):
        """Test 48"""
        with conf_page.expect_request(lambda req: COLOCATION_CONFIGS in req.url and req.method == 'GET'):
            cc.get_sync_button(conf_page).click()

    @staticmethod
    def test_sort_node_name(conf_page: Page):
        """Test 49"""
        name_columnheader = cc.get_columnheaders(conf_page)['name']

        name_columnheader.click() # first click -> ascending order
        node_names = cc.get_node_name(conf_page)
        node_names = [name.text_content() or "" for name in node_names]
        assert_that(node_names).is_equal_to(sorted(node_names))

        name_columnheader.click() # second click -> descending order
        node_names = cc.get_node_name(conf_page)
        node_names = [name.text_content() or "" for name in node_names]
        assert_that(node_names).is_equal_to(sorted(node_names, reverse=True))

    @staticmethod
    def test_filter_node_status(conf_page: Page):
        """Test 50"""
        cc.do_filter_status(conf_page, 'Active')

        node_status = cc.get_node_status_column(conf_page)
        for status in node_status:
            assert_that(status.text_content()).is_equal_to('Active')

    # not implemented yet
    # @staticmethod
    # def test_54_pagination(conf_page: Page):
    #     pass

    @staticmethod
    def test_all_node_are_switched_off_by_default(conf_page: Page):
        """Test 51"""
        node_switches = cc.get_colocation_switches(conf_page)
        for node_switch in node_switches:
            expect(node_switch).not_to_be_checked()

    @staticmethod
    def test_switch_on_off_nodes_front_end_back_end(conf_page: Page, api_context: APIRequestContext):
        """Test 52, 53"""
        node_list = fetch_all_node(api_context).get('items', [])
        assert_that(node_list).is_not_empty()
        node_name = node_list[0]["metadata"]["name"]
        # 初始状态下混部关闭
        assert_that(cc.get_node_switch_ischecked(conf_page, node_name)).is_false()
        # 
        cc.do_toggle_node_colocation(conf_page, node_name)
        conf_page.wait_for_timeout(10000) # Allow time for backend update
        assert_that(cc.get_node_switch_ischecked(conf_page, node_name)).is_true()
        colocation_options, _, _ = fetch_colocation_config(api_context)
        # 如果没有节点开启混部，该列表为空
        colocation_nodes = [node['name'] for node in colocation_options['nodesConfig']] \
            if colocation_options['nodesConfig'] else []
        assert_that(cc.get_node_switch_ischecked(conf_page, node_name)).is_true()
        assert_that(colocation_nodes).contains(node_name)
        # 再次点击后关闭
        cc.do_toggle_node_colocation(conf_page, node_name)
        conf_page.wait_for_timeout(10000) # Allow time for backend update
        assert_that(cc.get_node_switch_ischecked(conf_page, node_name)).is_false()
        colocation_options, _, _ = fetch_colocation_config(api_context)
        colocation_nodes = [node['name'] for node in colocation_options['nodesConfig']] \
            if colocation_options['nodesConfig'] else []
        assert_that(colocation_nodes).does_not_contain(node_name)

    @staticmethod
    def test_colocation_and_oversubscription(conf_page: Page, api_context: APIRequestContext):
        """Test 25, 26"""
        node_list = fetch_all_node(api_context).get('items', [])
        assert_that(node_list).is_not_empty()
        node_name = node_list[0]["metadata"]["name"]
        oversub_labels = ['kubernetes.io/be-cpu', 'kubernetes.io/be-memory']
        # 初始状态下超卖关闭
        assert_that(cc.get_node_switch_ischecked(conf_page, node_name)).is_false()
        # 一次点击后启用
        cc.do_toggle_node_colocation(conf_page, node_name)
        # 失败轮询，最多等60秒，每2秒检查一次
        found = False
        for _ in range(60):
            node_data = fetch_node(api_context, node_name)
            capacity = node_data.get('status', {}).get('capacity', {})
            allocatable = node_data.get('status', {}).get('allocatable', {})
            if all(label in capacity for label in oversub_labels) and \
                all(label in allocatable for label in oversub_labels):
                found = True
                break
            time.sleep(1)
        assert_that(found).is_true()
        # 再次点击后关闭
        cc.do_toggle_node_colocation(conf_page, node_name)
        # 删除标签直接生效
        found = True
        for _ in range(60):
            node_data = fetch_node(api_context, node_name)
            capacity = node_data.get('status', {}).get('capacity', {})
            allocatable = node_data.get('status', {}).get('allocatable', {})
            if all(label not in capacity for label in oversub_labels) and \
                all(label not in allocatable for label in oversub_labels):
                found = False
                break
            time.sleep(1)
        assert_that(found).is_false()


@pytest.fixture(scope='function')
def conf_modal_page(context: BrowserContext) -> Generator[Page, None, None]:
    """混部策略配置页面且打开配置浮窗"""
    page = context.new_page()
    page.goto('/container_platform/colocation/ColocationConfiguration')
    page.wait_for_selector('.colocation-website-table-row') # wait for table to be populated
    page.get_by_role('button', name='混部策略参数配置').click()
    yield page
    page.close()


class TestColocationConfigurationModal:
    """
    @description 测试混部策略配置弹窗的主要交互，包括：
    - 打开弹窗
    - 关闭弹窗
    - 取消配置
    """
    @staticmethod
    def test_open_modal(conf_modal_page: Page):
        """Test 55"""
        expect(cc.get_modal(conf_modal_page)).to_be_visible()

    @staticmethod
    def test_close_modal(conf_modal_page: Page):
        """Test 57"""
        cc.do_close_modal(conf_modal_page)
        expect(cc.get_modal(conf_modal_page)).not_to_be_visible()

    @staticmethod
    def test_cancel_modal(conf_modal_page: Page):
        """Test 58"""
        switches = cc.get_switched(conf_modal_page)
        initial_states = [sw.is_checked() for sw in switches]

        for sw in switches:
            sw.click()
        cc.do_click_modal_cancel(conf_modal_page)

        cc.do_open_modal(conf_modal_page)
        switches = cc.get_switched(conf_modal_page)
        new_states = [sw.is_checked() for sw in switches]
        assert_that(initial_states).is_equal_to(new_states)


class TestColocationConfigurationOps:
    """
    @description 测试混部策略配置各参数的更改操作，包括：
    - 通过策略配置弹窗表单更改集群混部配置
    - 负载感知调度
    - 真实负载调度阈值开关
    - 离线负载水位线驱逐
    """
    @pytest.mark.order(1)
    @staticmethod
    def test_usage_plugin_switch_unchecked_by_default(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 60"""
        expect(cc.get_usage_plugin_switch(conf_modal_page)).not_to_be_checked()
        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['enable']).is_false()

    @pytest.mark.order(2)
    @staticmethod
    def test_toggle_usage_plugin_switch_to_show_hide_threshold_switch(conf_modal_page: Page):
        """Test 61"""
        expect(cc.get_usage_threshold_switch(conf_modal_page)).not_to_be_visible()
        cc.do_toggle_usage_plugin_switch(conf_modal_page)
        expect(cc.get_usage_threshold_switch(conf_modal_page)).to_be_visible()

    @pytest.mark.order(3)
    @staticmethod
    def test_turn_on_usage_plugin(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 62"""
        cc.do_toggle_usage_plugin_switch(conf_modal_page)
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['enable']).is_true()

        volcano_scheduler_config = fetch_volcano_config(api_context)
        has_priority = any(
            any(plugin.get('name') == 'priority' for plugin in tier.get('plugins', []))
            for tier in volcano_scheduler_config.get('tiers', [])
        )
        has_usage = any(
            any(
                plugin.get('name') == 'usage' and
                'arguments' in plugin and
                'thresholds' in plugin['arguments'] and
                'cpu' in plugin['arguments']['thresholds'] and
                'mem' in plugin['arguments']['thresholds']
                for plugin in tier.get('plugins', [])
            )
            for tier in volcano_scheduler_config.get('tiers', [])
        )
        assert_that(has_priority).is_true()
        assert_that(has_usage).is_true()

    @pytest.mark.order(4)
    @staticmethod
    def test_usage_threshold_switch_unchecked_by_default(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 64"""
        expect(cc.get_usage_threshold_switch(conf_modal_page)).not_to_be_checked()

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['enable']).is_false()

    @pytest.mark.order(5)
    @staticmethod
    def test_toggle_usage_threshold_switch_to_show_hide_inputs(conf_modal_page: Page):
        """Test 65"""
        cpu_threshold_textbox, _ = cc.get_usage_threshold_textbox(conf_modal_page)
        expect(cpu_threshold_textbox).not_to_be_visible()
        cc.do_toggle_usage_threshold_switch(conf_modal_page)
        expect(cpu_threshold_textbox).to_be_visible()

    @pytest.mark.order(6)
    @staticmethod
    def test_turn_on_usage_threshold_with_default_thresholds(conf_modal_page: Page, api_context):
        """Test 66, 71"""
        cc.do_toggle_usage_threshold_switch(conf_modal_page)
        # default thresholds
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        expect(cpu_textbox).to_have_value('60')
        expect(mem_textbox).to_have_value('60')

        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['enable']).is_true()
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['cpu']).is_equal_to(60)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['memory']).is_equal_to(60)

    @pytest.mark.order(7)
    @staticmethod
    def test_maximum_usage_threshold(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 67, 72"""
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('100')
        mem_textbox.fill('100')
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['enable']).is_true()
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['cpu']).is_equal_to(100)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['memory']).is_equal_to(100)

    @pytest.mark.order(8)
    @staticmethod
    def test_invalid_usage_thresholds(conf_modal_page: Page):
        """Test 68, 69, 73, 74"""
        request_fired = False

        def handle_request(request):
            nonlocal request_fired
            if COLOCATION_CONFIGS in request.url and request.method == 'POST':
                request_fired = True
        conf_modal_page.on('request', handle_request)

        # invalid cpu threshold
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        mem_textbox.fill('50')
        cpu_textbox.fill('-1')
        expect(conf_modal_page.get_by_text('请输入有效的数字节点的CPU')).to_be_visible()
        cpu_textbox.fill('101')
        expect(conf_modal_page.get_by_text('0-100之间的数值节点的CPU')).to_be_visible()
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')
        assert_that(request_fired).is_false()

        # invalid memory threshold
        request_fired = False # Reset for next check
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('50')
        mem_textbox.fill('-1')
        expect(conf_modal_page.get_by_text('请输入有效的数字节点的内存')).to_be_visible()
        mem_textbox.fill('101')
        expect(conf_modal_page.get_by_text('请输入0-100之间的数值节点的内存')).to_be_visible()
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')
        assert_that(request_fired).is_false()

        # invalid float
        request_fired = False # Reset for next check
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('83.333')
        expect(conf_modal_page.get_by_text('最多两位小数节点的CPU')).to_be_visible()
        mem_textbox.fill('83.333')
        expect(conf_modal_page.get_by_text('最多两位小数节点的内存')).to_be_visible()
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')
        assert_that(request_fired).is_false()

    @pytest.mark.order(9)
    @staticmethod
    def test_valid_cpu_mem_thresholds(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 70, 75"""
        cpu_textbox, mem_textbox = cc.get_usage_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('83.33')
        mem_textbox.fill('83.33')
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['enable']).is_true()
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['cpu']).is_equal_to(83.33)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['memory']).is_equal_to(83.33)

    @pytest.mark.order(10)
    @staticmethod
    def test_turn_off_usage_plugin(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 63"""
        cc.do_toggle_usage_plugin_switch(conf_modal_page)
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, volcano_scheduler_options, _ = fetch_colocation_config(api_context)
        assert_that(volcano_scheduler_options['usagePlugin']['usageThreshold']['enable']).is_false()

    @pytest.mark.order(11)
    @staticmethod
    def test_eviction_switch_unchecked_by_default(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 84"""
        expect(cc.get_eviction_switch(conf_modal_page)).not_to_be_checked()
        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_false()

    @pytest.mark.order(12)
    @staticmethod
    def test_toggle_eviction_switch_to_show_hide_inputs(conf_modal_page: Page):
        """Test 85"""
        cpu_textbox, _ = cc.get_eviction_threshold_textbox(conf_modal_page)
        expect(cpu_textbox).not_to_be_visible()
        cc.do_toggle_eviction_switch(conf_modal_page)
        expect(cpu_textbox).to_be_visible()

    @pytest.mark.order(13)
    @staticmethod
    def test_turn_on_eviction(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 86"""
        cc.do_toggle_eviction_switch(conf_modal_page)
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_true()

    @pytest.mark.order(14)
    @staticmethod
    def test_default_eviction_thresholds(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 88, 94"""
        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        expect(cpu_textbox).to_have_value('60')
        expect(mem_textbox).to_have_value('60')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_true()
        assert_that(rubik_options['eviction']['cpuevict']['threshold']).is_equal_to(60)
        assert_that(rubik_options['eviction']['memoryevict']['threshold']).is_equal_to(60)

    @pytest.mark.order(15)
    @staticmethod
    def test_minimum_eviction_thresholds(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 89, 95"""
        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('1')
        mem_textbox.fill('1')
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_true()
        assert_that(rubik_options['eviction']['cpuevict']['threshold']).is_equal_to(1)
        assert_that(rubik_options['eviction']['memoryevict']['threshold']).is_equal_to(1)

    @pytest.mark.order(16)
    @staticmethod
    def test_maximum_eviction_thresholds(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 90, 96"""
        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('99')
        mem_textbox.fill('99')
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_true()
        assert_that(rubik_options['eviction']['cpuevict']['threshold']).is_equal_to(99)
        assert_that(rubik_options['eviction']['memoryevict']['threshold']).is_equal_to(99)

    @pytest.mark.order(17)
    @staticmethod
    def test_invalid_eviction_thresholds(conf_modal_page: Page):
        """Test 91, 92, 97, 98"""
        request_fired = False

        def handle_request(request):
            nonlocal request_fired
            if COLOCATION_CONFIGS in request.url and request.method == 'POST':
                request_fired = True
        conf_modal_page.on('request', handle_request)

        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        mem_textbox.fill('50')
        cpu_textbox.fill('0')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的CPU')).to_be_visible()
        cpu_textbox.fill('100')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的CPU')).to_be_visible()
        cpu_textbox.fill('50.5')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的CPU')).to_be_visible()
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')
        assert_that(request_fired).is_false()

        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        mem_textbox.fill('0')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的内存')).to_be_visible()
        mem_textbox.fill('100')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的内存')).to_be_visible()
        mem_textbox.fill('50.5')
        expect(conf_modal_page.get_by_text('请输入1-99之间的整数当节点上所有Pod的内存')).to_be_visible()
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')
        assert_that(request_fired).is_false()

    @pytest.mark.order(18)
    @staticmethod
    def test_valid_eviction_thresholds(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 93, 99"""
        cpu_textbox, mem_textbox = cc.get_eviction_threshold_textbox(conf_modal_page)
        cpu_textbox.fill('50')
        mem_textbox.fill('50')
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_true()
        assert_that(rubik_options['eviction']['cpuevict']['threshold']).is_equal_to(50)
        assert_that(rubik_options['eviction']['memoryevict']['threshold']).is_equal_to(50)

    @pytest.mark.order(19)
    @staticmethod
    def test_turn_off_eviction(conf_modal_page: Page, api_context: APIRequestContext):
        """Test 87"""
        cc.do_toggle_eviction_switch(conf_modal_page)
        cc.do_click_modal_confirm(conf_modal_page)
        conf_modal_page.wait_for_load_state('networkidle')

        _, _, rubik_options = fetch_colocation_config(api_context)
        assert_that(rubik_options['eviction']['enable']).is_false()

    @staticmethod
    def allow_turn_on_usage_plugin_with_colocation_off(conf_page: Page):
        """Test 100, 102"""
        node_switches = cc.get_colocation_switches(conf_page)
        for sw in node_switches:
            if sw.is_checked():
                sw.click()
        cc.do_open_modal(conf_page)
        cc.do_toggle_usage_plugin_switch(conf_page)
        cc.do_click_modal_confirm(conf_page)

        for sw in node_switches:
            expect(sw).not_to_be_checked()

        cc.do_open_modal(conf_page)
        cc.do_toggle_usage_plugin_switch(conf_page)
        cc.do_click_modal_confirm(conf_page)

        for sw in node_switches:
            expect(sw).not_to_be_checked()

    @staticmethod
    def allow_turn_on_eviction_with_colocation_off(conf_page: Page):
        """Test 101, 103"""
        node_switches = cc.get_colocation_switches(conf_page)
        for sw in node_switches:
            if sw.is_checked():
                sw.click()
        cc.do_open_modal(conf_page)
        cc.do_toggle_eviction_switch(conf_page)
        cc.do_click_modal_confirm(conf_page)

        for sw in node_switches:
            expect(sw).not_to_be_checked()

        cc.do_open_modal(conf_page)
        cc.do_toggle_eviction_switch(conf_page)
        cc.do_click_modal_confirm(conf_page)

        for sw in node_switches:
            expect(sw).not_to_be_checked()

